001 /* 002 * PairwiseAlignmentFrame.java 003 * 004 * Copyright 2003 Sergio Anibal de Carvalho Junior 005 * 006 * This file is part of NeoBio. 007 * 008 * NeoBio is free software; you can redistribute it and/or modify it under the terms of 009 * the GNU General Public License as published by the Free Software Foundation; either 010 * version 2 of the License, or (at your option) any later version. 011 * 012 * NeoBio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 013 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 014 * PURPOSE. See the GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License along with NeoBio; 017 * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, 018 * Boston, MA 02111-1307, USA. 019 * 020 * Proper attribution of the author as the source of the software would be appreciated. 021 * 022 * Sergio Anibal de Carvalho Junior mailto:sergioanibaljr@users.sourceforge.net 023 * Department of Computer Science http://www.dcs.kcl.ac.uk 024 * King's College London, UK http://www.kcl.ac.uk 025 * 026 * Please visit http://neobio.sourceforge.net 027 * 028 * This project was supervised by Professor Maxime Crochemore. 029 * 030 */ 031 032 package neobio.gui; 033 034 import neobio.alignment.*; 035 036 import java.io.*; 037 import java.awt.*; 038 import java.awt.event.*; 039 import javax.swing.*; 040 import javax.swing.border.*; 041 import javax.swing.event.*; 042 043 /** 044 * This class is the internal frame of NeoBio's graphical interface for computing pairwise 045 * sequence alignments using one of the the algorithms provided in the {@link 046 * neobio.alignment} package. 047 * 048 * @author Sergio A. de Carvalho Jr. 049 */ 050 public class PairwiseAlignmentFrame extends JInternalFrame 051 { 052 private static int window_number = 1; 053 054 private Frame parent_frame; 055 056 private JPanel input_panel, scoring_panel, algorithm_panel, output_panel; 057 private JPanel progress_tab_panel, output_tab_panel; 058 private JTextField seq1_field, seq2_field, matrix_field, output_field; 059 private JTextField match_field, mismatch_field, gap_field; 060 private JTextArea progress_area, output_area; 061 private JButton find_seq1_button, find_seq2_button, find_output_button; 062 private JButton find_matrix_button, run_button; 063 private JComboBox algorithm_combo; 064 private JTabbedPane output_tab; 065 private JRadioButton screen_button, file_button, basic_button, matrix_button; 066 private ButtonGroup scoring_group, output_group; 067 private JLabel seq1_label, seq2_label; 068 private JLabel match_label, mismatch_label, gap_label; 069 070 private JFileChooser find_dialog; 071 072 private boolean output_to_file, basic_scheme; 073 074 private String[] algorithm_name = {"Needleman & Wunsch (global alignment)", 075 "Smith & Waterman (local alignment)", 076 "Crochemore, Landau & Ziv-Ukelson for global alignment", 077 "Crochemore, Landau & Ziv-Ukelson for local alignment"}; 078 079 private PairwiseAlignmentAlgorithm[] algorithm = {new NeedlemanWunsch(), 080 new SmithWaterman(), 081 new CrochemoreLandauZivUkelsonGlobalAlignment(), 082 new CrochemoreLandauZivUkelsonLocalAlignment()}; 083 084 /** 085 * Creates a new instance of the internal frame. 086 * 087 * @param parent_frame the parent frame 088 */ 089 public PairwiseAlignmentFrame (Frame parent_frame) 090 { 091 this.parent_frame = parent_frame; 092 initComponents(); 093 } 094 095 private void initComponents() 096 { 097 JComponent pane; 098 GridBagConstraints c; 099 100 setIconifiable(true); 101 setMaximizable(true); 102 setResizable(true); 103 setClosable(true); 104 setTitle("Pairwise Sequence Alignment " + window_number++); 105 setMinimumSize(new Dimension(500, 500)); 106 107 pane = (JComponent) getContentPane(); 108 pane.setLayout(new GridBagLayout()); 109 110 c = new GridBagConstraints(); 111 c.insets = new Insets (4, 4, 4, 4); 112 c.fill = GridBagConstraints.BOTH; 113 c.weightx = 1.0; c.weighty = 0; 114 115 // input panel 116 input_panel = new JPanel (); 117 add (pane, input_panel, c, 0, 0); 118 119 // scoring panel 120 scoring_panel = new JPanel (); 121 add (pane, scoring_panel, c, 0, 1); 122 123 // output panel 124 output_panel = new JPanel (); 125 add (pane, output_panel, c, 0, 2); 126 127 // algorithm panel 128 algorithm_panel = new JPanel (); 129 add (pane, algorithm_panel, c, 0, 3); 130 131 c.weightx = 1.0; c.weighty = 1.0; 132 133 // output tab 134 output_tab = new JTabbedPane(); 135 add (pane, output_tab, c, 0, 4); 136 137 find_dialog = new JFileChooser(); 138 find_dialog.setDialogTitle("Find..."); 139 find_dialog.setDialogType(JFileChooser.OPEN_DIALOG ); 140 141 // ***************** INPUT PANEL ***************** 142 input_panel.setLayout(new GridBagLayout()); 143 input_panel.setBorder(BorderFactory.createTitledBorder(new EtchedBorder( 144 EtchedBorder.LOWERED), "Input")); 145 146 seq1_label = new JLabel("Sequence 1:"); 147 seq2_label = new JLabel("Sequence 2:"); 148 149 seq1_field = new JTextField(); 150 seq1_field.addCaretListener (new CaretListener() 151 { 152 public void caretUpdate (CaretEvent e) 153 { 154 checkRunButtonStatus (); 155 } 156 }); 157 158 seq2_field = new JTextField(); 159 seq2_field.addCaretListener (new CaretListener() 160 { 161 public void caretUpdate (CaretEvent e) 162 { 163 checkRunButtonStatus (); 164 } 165 }); 166 167 find_seq1_button = new JButton("Find..."); 168 find_seq1_button.addActionListener (new ActionListener() 169 { 170 public void actionPerformed (ActionEvent e) 171 { 172 findSeq1ButtonActionPerformed(); 173 } 174 }); 175 176 find_seq2_button = new JButton("Find..."); 177 find_seq2_button.addActionListener (new ActionListener() 178 { 179 public void actionPerformed (ActionEvent e) 180 { 181 findSeq2ButtonActionPerformed(); 182 } 183 }); 184 185 c.weightx = 0; c.weighty = 0; c.anchor = GridBagConstraints.EAST; 186 add (input_panel, seq1_label, c, 0, 0); 187 add (input_panel, seq2_label, c, 0, 1); 188 189 c.anchor = GridBagConstraints.CENTER; 190 add (input_panel, find_seq1_button, c, 2, 0); 191 add (input_panel, find_seq2_button, c, 2, 1); 192 193 c.weightx = 1.0; c.fill = GridBagConstraints.HORIZONTAL; 194 add (input_panel, seq1_field, c, 1, 0); 195 add (input_panel, seq2_field, c, 1, 1); 196 197 // ***************** SCORING SCHEME PANEL ***************** 198 scoring_panel.setLayout(new GridBagLayout()); 199 scoring_panel.setBorder(BorderFactory.createTitledBorder(new EtchedBorder( 200 EtchedBorder.LOWERED), "Scoring Scheme")); 201 202 basic_scheme = true; 203 basic_button = new JRadioButton("Basic:"); 204 basic_button.setSelected(true); 205 basic_button.addItemListener (new ItemListener() 206 { 207 public void itemStateChanged (ItemEvent e) 208 { 209 schemeOptionStateChanged(); 210 } 211 }); 212 213 matrix_button = new JRadioButton("Substitution Matrix:"); 214 matrix_button.addItemListener (new ItemListener() 215 { 216 public void itemStateChanged (ItemEvent e) 217 { 218 schemeOptionStateChanged(); 219 } 220 }); 221 222 match_label = new JLabel("Match:"); 223 mismatch_label = new JLabel ("Mismatch:"); 224 gap_label = new JLabel ("Gap:"); 225 226 match_field = new JTextField("1", 2); 227 match_field.setHorizontalAlignment(JTextField.RIGHT); 228 match_field.addCaretListener (new CaretListener() 229 { 230 public void caretUpdate (CaretEvent e) 231 { 232 checkRunButtonStatus (); 233 } 234 }); 235 236 mismatch_field = new JTextField("-1", 2); 237 mismatch_field.setHorizontalAlignment(JTextField.RIGHT); 238 mismatch_field.addCaretListener (new CaretListener() 239 { 240 public void caretUpdate (CaretEvent e) 241 { 242 checkRunButtonStatus (); 243 } 244 }); 245 246 gap_field = new JTextField("-1", 2); 247 gap_field.setHorizontalAlignment(JTextField.RIGHT); 248 gap_field.addCaretListener (new CaretListener() 249 { 250 public void caretUpdate (CaretEvent e) 251 { 252 checkRunButtonStatus (); 253 } 254 }); 255 256 matrix_field = new JTextField(); 257 matrix_field.setEnabled(false); 258 matrix_field.addCaretListener (new CaretListener() 259 { 260 public void caretUpdate (CaretEvent e) 261 { 262 checkRunButtonStatus (); 263 } 264 }); 265 266 find_matrix_button = new JButton("Find..."); 267 find_matrix_button.setEnabled(false); 268 find_matrix_button.addActionListener (new ActionListener() 269 { 270 public void actionPerformed (ActionEvent e) 271 { 272 findMatrixButtonActionPerformed(); 273 } 274 }); 275 276 scoring_group = new ButtonGroup (); 277 scoring_group.add(basic_button); 278 scoring_group.add(matrix_button); 279 280 c.weightx = 0; c.fill = GridBagConstraints.NONE; 281 c.anchor = GridBagConstraints.WEST; 282 add (scoring_panel, basic_button, c, 0, 0); 283 284 c.anchor = GridBagConstraints.EAST; 285 add (scoring_panel, match_label, c, 1, 0); 286 add (scoring_panel, mismatch_label, c, 3, 0); 287 add (scoring_panel, gap_label, c, 5, 0); 288 289 c.anchor = GridBagConstraints.WEST; 290 add (scoring_panel, matrix_button, c, 0, 1); 291 292 c.anchor = GridBagConstraints.CENTER; 293 add (scoring_panel, find_matrix_button, c, 7, 1); 294 295 c.weightx = 1.0 / 3; c.fill = GridBagConstraints.HORIZONTAL; 296 add (scoring_panel, match_field, c, 2, 0); 297 add (scoring_panel, mismatch_field, c, 4, 0); 298 add (scoring_panel, gap_field, c, 6, 0); 299 300 c.weightx = 1.0; c.gridwidth = 6; 301 add (scoring_panel, matrix_field, c, 1, 1); 302 c.gridwidth = 1; 303 304 // ***************** OUTPUT PANEL ***************** 305 output_panel.setLayout(new GridBagLayout()); 306 output_panel.setBorder(BorderFactory.createTitledBorder(new EtchedBorder( 307 EtchedBorder.LOWERED), "Output")); 308 309 screen_button = new JRadioButton("Screen"); 310 screen_button.setSelected(true); 311 312 output_to_file = false; 313 file_button = new JRadioButton("File:"); 314 file_button.addItemListener (new ItemListener() 315 { 316 public void itemStateChanged (ItemEvent e) 317 { 318 outputOptionStateChanged(); 319 } 320 }); 321 322 output_field = new JTextField(); 323 output_field.setEnabled(false); 324 output_field.addCaretListener (new CaretListener() 325 { 326 public void caretUpdate (CaretEvent e) 327 { 328 checkRunButtonStatus (); 329 } 330 }); 331 332 find_output_button = new JButton("Find..."); 333 find_output_button.setEnabled(false); 334 find_output_button.addActionListener (new ActionListener() 335 { 336 public void actionPerformed (ActionEvent e) 337 { 338 findOutputButtonActionPerformed(); 339 } 340 }); 341 342 output_group = new ButtonGroup (); 343 output_group.add(screen_button); 344 output_group.add(file_button); 345 346 c.weightx = 0; c.weighty = 0; c.fill = GridBagConstraints.NONE; 347 add (output_panel, screen_button, c, 0, 0); 348 add (output_panel, file_button, c, 1, 0); 349 add (output_panel, find_output_button, c, 3, 0); 350 351 c.weightx = 1.0; c.weighty = 0; c.fill = GridBagConstraints.HORIZONTAL; 352 add (output_panel, output_field, c, 2, 0); 353 354 // ***************** ALGORITHM PANEL ***************** 355 algorithm_panel.setLayout(new GridBagLayout()); 356 algorithm_panel.setBorder(BorderFactory.createTitledBorder(new EtchedBorder( 357 EtchedBorder.LOWERED), "Alignment Algorithm")); 358 359 algorithm_combo = new JComboBox(algorithm_name); 360 361 run_button = new JButton("Run"); 362 run_button.setEnabled(false); 363 run_button.addActionListener (new ActionListener() 364 { 365 public void actionPerformed (ActionEvent e) 366 { 367 runButtonActionPerformed(); 368 } 369 }); 370 371 372 c.weightx = 1.0; c.weighty = 0; c.fill = GridBagConstraints.HORIZONTAL; 373 add (algorithm_panel, algorithm_combo, c, 0, 0); 374 375 c.weightx = 0; c.weighty = 0; c.fill = GridBagConstraints.NONE; 376 add (algorithm_panel, run_button, c, 1, 0); 377 378 // ***************** OUTPUT TAB ***************** 379 progress_area = new JTextArea (); 380 progress_area.setEditable (false); 381 progress_area.setBorder (BorderFactory.createBevelBorder(BevelBorder.LOWERED)); 382 progress_tab_panel = new JPanel (); 383 progress_tab_panel.setLayout (new GridLayout()); 384 progress_tab_panel.add (new JScrollPane (progress_area)); 385 output_tab.addTab ("Progress", progress_tab_panel); 386 387 output_area = new JTextArea (); 388 output_area.setEditable (false); 389 output_area.setBorder (BorderFactory.createBevelBorder(BevelBorder.LOWERED)); 390 output_area.setFont (new Font("Monospaced", Font.PLAIN, 12)); 391 output_tab_panel = new JPanel(); 392 output_tab_panel.setLayout (new GridLayout()); 393 output_tab_panel.add (new JScrollPane (output_area)); 394 output_tab.addTab ("Output", output_tab_panel); 395 } 396 397 private void add (JComponent a, JComponent b, GridBagConstraints c, int x, int y) 398 { 399 c.gridx = x; 400 c.gridy = y; 401 a.add (b, c); 402 } 403 404 private void findSeq1ButtonActionPerformed () 405 { 406 int c = find_dialog.showOpenDialog (this); 407 408 if (c != JFileChooser.APPROVE_OPTION) return; 409 410 seq1_field.setText (find_dialog.getSelectedFile().getPath()); 411 } 412 413 private void findSeq2ButtonActionPerformed () 414 { 415 int c = find_dialog.showOpenDialog (this); 416 417 if (c != JFileChooser.APPROVE_OPTION) return; 418 419 seq2_field.setText (find_dialog.getSelectedFile().getPath()); 420 } 421 422 private void findMatrixButtonActionPerformed () 423 { 424 int c = find_dialog.showOpenDialog (this); 425 426 if (c != JFileChooser.APPROVE_OPTION) return; 427 428 matrix_field.setText (find_dialog.getSelectedFile().getPath()); 429 } 430 431 private void findOutputButtonActionPerformed () 432 { 433 int c = find_dialog.showOpenDialog (this); 434 435 if (c != JFileChooser.APPROVE_OPTION) return; 436 437 output_field.setText (find_dialog.getSelectedFile().getPath()); 438 } 439 440 private void schemeOptionStateChanged () 441 { 442 basic_scheme = basic_button.isSelected(); 443 444 match_label.setEnabled(basic_scheme); 445 match_field.setEnabled(basic_scheme); 446 mismatch_label.setEnabled(basic_scheme); 447 mismatch_field.setEnabled(basic_scheme); 448 gap_label.setEnabled(basic_scheme); 449 gap_field.setEnabled(basic_scheme); 450 451 matrix_field.setEnabled (!basic_scheme); 452 find_matrix_button.setEnabled (!basic_scheme); 453 454 checkRunButtonStatus(); 455 } 456 457 private void outputOptionStateChanged () 458 { 459 output_to_file = file_button.isSelected(); 460 461 output_field.setEnabled (output_to_file); 462 find_output_button.setEnabled (output_to_file); 463 464 checkRunButtonStatus(); 465 } 466 467 private void checkRunButtonStatus () 468 { 469 boolean run = true; 470 471 if (seq1_field.getText().length() == 0 || seq2_field.getText().length() == 0) 472 { 473 run = false; 474 } 475 else 476 { 477 if (file_button.isSelected() && output_field.getText().length() == 0) 478 { 479 run = false; 480 } 481 else 482 { 483 if (matrix_button.isSelected()) 484 { 485 if (matrix_field.getText().length() == 0) 486 { 487 run = false; 488 } 489 } 490 else 491 { 492 if (match_field.getText().length() == 0 493 || mismatch_field.getText().length() == 0 494 || gap_field.getText().length() == 0) 495 { 496 run = false; 497 } 498 } 499 } 500 } 501 502 if ((run_button.isEnabled() && !run) || (!run_button.isEnabled() && run)) 503 run_button.setEnabled(run); 504 } 505 506 private void runButtonActionPerformed () 507 { 508 ScoringScheme scoring; 509 PairwiseAlignment alignment; 510 FileReader seq1_file, seq2_file, matrix_file; 511 BufferedWriter output_file; 512 String seq1_filename, seq2_filename; 513 String matrix_filename, output_filename, message; 514 int alg, match, mismatch, gap; 515 long start, elapsed; 516 517 alg = algorithm_combo.getSelectedIndex(); 518 519 output_tab.setSelectedIndex(0); 520 521 output_area.setText (""); 522 523 // ***************** SET SCORING SCHEME ***************** 524 if (basic_scheme) 525 { 526 progress_area.setText ("Creating scoring scheme... "); 527 try 528 { 529 match = Integer.parseInt (match_field.getText()); 530 mismatch = Integer.parseInt (mismatch_field.getText()); 531 gap = Integer.parseInt (gap_field.getText()); 532 533 scoring = new BasicScoringScheme (match, mismatch, gap); 534 algorithm[alg].setScoringScheme(scoring); 535 progress_area.append ("OK"); 536 } 537 catch (NumberFormatException e) 538 { 539 message = "Invalid scoring arguments."; 540 progress_area.append ("\n" + message); 541 showError (message); 542 return; 543 } 544 } 545 else 546 { 547 matrix_filename = matrix_field.getText (); 548 progress_area.setText ("Loading matrix file... "); 549 try 550 { 551 matrix_file = new FileReader (matrix_filename); 552 } 553 catch (FileNotFoundException e) 554 { 555 message = "File \"" + matrix_filename + "\" not found."; 556 progress_area.append("\n" + message); 557 showError (message); 558 return; 559 } 560 561 try 562 { 563 try 564 { 565 scoring = new ScoringMatrix (matrix_file); 566 algorithm[alg].setScoringScheme(scoring); 567 progress_area.append ("OK"); 568 } 569 catch (InvalidScoringMatrixException e) 570 { 571 matrix_file.close(); 572 message = "Invalid matrix file \"" + matrix_filename + "\"."; 573 progress_area.append ("\n" + message); 574 showError (message); 575 return; 576 } 577 matrix_file.close(); 578 } 579 catch (IOException e) 580 { 581 message = "Error reading file."; 582 progress_area.append("\n" + message); 583 showError (message); 584 return; 585 } 586 } 587 588 // ***************** LOAD SEQUENCES ***************** 589 progress_area.append ("\n\nLoading sequences... "); 590 591 seq1_filename = seq1_field.getText (); 592 try 593 { 594 seq1_file = new FileReader (seq1_filename); 595 } 596 catch (FileNotFoundException e) 597 { 598 message = "File \"" + seq1_filename +"\" not found."; 599 progress_area.append("\n" + message); 600 showError (message); 601 return; 602 } 603 604 seq2_filename = seq2_field.getText (); 605 try 606 { 607 seq2_file = new FileReader (seq2_filename); 608 } 609 catch (FileNotFoundException e) 610 { 611 message = "File \"" + seq2_filename +"\" not found."; 612 progress_area.append("\n" + message); 613 showError (message); 614 return; 615 } 616 617 try 618 { 619 try 620 { 621 start = System.currentTimeMillis(); 622 algorithm[alg].loadSequences (seq1_file, seq2_file); 623 elapsed = System.currentTimeMillis() - start; 624 progress_area.append ("OK"); 625 progress_area.append ("\n[ Elapsed time: " + elapsed + " milliseconds ]"); 626 627 } 628 catch (InvalidSequenceException e) 629 { 630 seq1_file.close(); 631 seq2_file.close(); 632 message = "Invalid sequence files."; 633 progress_area.append ("\n" + message); 634 showError (message); 635 return; 636 } 637 seq1_file.close(); 638 seq2_file.close(); 639 } 640 catch (IOException e) 641 { 642 message = "Error reading sequence files."; 643 progress_area.append("\n" + message); 644 showError (message); 645 return; 646 } 647 648 // ***************** EXECUTE ALGORITHM ***************** 649 progress_area.append("\n\nRunning " + algorithm_combo.getSelectedItem() + "... "); 650 try 651 { 652 start = System.currentTimeMillis(); 653 alignment = algorithm[alg].getPairwiseAlignment(); 654 elapsed = System.currentTimeMillis() - start; 655 progress_area.append ("OK"); 656 progress_area.append ("\n[ Elapsed time: " + elapsed + " milliseconds ]"); 657 } 658 catch (IncompatibleScoringSchemeException e) 659 { 660 message = "Scoring matrix is not compatible with loaded sequences."; 661 progress_area.append ("\n" + message); 662 showError (message); 663 return; 664 } 665 catch (OutOfMemoryError e) 666 { 667 message = "Insufficient memory to compute an alignment"; 668 progress_area.append ("\n" + message); 669 showError (message); 670 return; 671 } 672 673 // ***************** DISPLAY / SAVE OUTPUT ***************** 674 if (output_to_file) 675 { 676 output_filename = output_field.getText (); 677 progress_area.append ("\n\nSaving alignment... "); 678 try 679 { 680 int length = alignment.getGappedSequence1().length(); 681 682 output_file = new BufferedWriter(new FileWriter (output_filename)); 683 output_file.write(alignment.getGappedSequence1(), 0, length); 684 output_file.newLine(); 685 output_file.write(alignment.getScoreTagLine(), 0, length); 686 output_file.newLine(); 687 output_file.write(alignment.getGappedSequence2(), 0, length); 688 output_file.newLine(); 689 String tmp = "Score: " + alignment.getScore(); 690 output_file.write(tmp, 0, tmp.length()); 691 output_file.close(); 692 } 693 catch (IOException e) 694 { 695 message = "Error writing file \"" + output_filename +"\"."; 696 progress_area.append("\n" + message); 697 showError (message); 698 return; 699 } 700 progress_area.append ("OK"); 701 } 702 else 703 { 704 output_area.setText (alignment.toString()); 705 output_tab.setSelectedIndex(1); 706 } 707 } 708 709 private void showError (String message) 710 { 711 JOptionPane.showMessageDialog(this, message, "Error", JOptionPane.ERROR_MESSAGE); 712 } 713 }